#include "../interface/T_gl_SceneGraph.h"

#include "../rtCommon/F_trace.h"

#pragma warning(disable:4996)

C_gl_SceneGraph::~C_gl_SceneGraph()
{
}

bool	C_gl_SceneGraph::Deserialize(char *pFileName)
{
	NVSHARE::FastXml *pMyXML = NVSHARE::createFastXml();

	bool result = pMyXML->processXmlFile(pFileName, this);

	NVSHARE::releaseFastXml(pMyXML);

	if (result) {
		for (uint iAsset = 0; iAsset < m_AssetList.size(); iAsset++)
			m_AssetList[iAsset]->Build(e_SpatialTree_Bvh);
	}
	return result;
}

bool	C_gl_SceneGraph::processElement(const char *elementName, 
																			NxI32 argc, const char **argv, 
																			const char *elementData, NxI32 lineno)
{
	static int matrixOffset = 0;
	int r = _heapchk();

	if (strcmp(elementName, "SceneGraph") == 0)
		return true;

	if (strcmp(elementName, "MaterialList") == 0 && argc == 2 && 
			strcmp(argv[0], "count") == 0)
	{
		int nMaterialListCount = 0;
		sscanf(argv[1], "%d", &nMaterialListCount);
		m_BaseMaterialList.reserve(nMaterialListCount);

		m_pBaseMaterial = new T_gl_BaseMaterial<uchar4, uchar>();

		T_gl_BaseMaterial<uchar4, uchar>* pGlBaseMaterial = (T_gl_BaseMaterial<uchar4, uchar>* )m_pBaseMaterial;

		pGlBaseMaterial->Create(nMaterialListCount * 4, (I_api_Device *) m_pDevice);
	}

	if (strcmp(elementName, "BaseMaterial") == 0 && argc == 2 && 
			strcmp(argv[0], "path") == 0)
	{
		T_gl_BaseMaterial<uchar4, uchar> * pBaseMaterial = new T_gl_BaseMaterial<uchar4, uchar>();

		pBaseMaterial->Create(4, (T_gl_BaseMaterial<uchar4, uchar>* ) m_pBaseMaterial);

		pBaseMaterial->Deserialize(argv[1]);

		m_BaseMaterialList.push_back(pBaseMaterial);
	}

	if (strcmp(elementName, "AssetList") == 0 && argc == 6 && 
			strcmp(argv[0], "count") == 0 && 
			strcmp(argv[2], "faces") == 0 &&
			strcmp(argv[4], "vertices") == 0)
	{
		int nAssetListCount = 0;
		sscanf(argv[1], "%d", &nAssetListCount);
		m_AssetList.reserve(nAssetListCount);
		sscanf(argv[3], "%d", &m_nFaceCount);
		sscanf(argv[5], "%d", &m_nVertexCount);
		
		m_pShared = new C_gl_Asset();
		m_pShared->Create(m_nVertexCount, m_nFaceCount*3, e_Asset_Data_Pos | 
																											e_Asset_Data_Idx | 
																											e_Asset_Data_Nml | 
																											e_Asset_Data_Tree, m_pDevice);

		m_pPosIdx = new T_Buffer_GL<int>();
		m_pPosIdx->Create(m_nFaceCount*3, m_pDevice);

		m_pShared->m_pTree->Create(e_SpatialTree_Data_PrimitiveBI | e_SpatialTree_Data_PrimIdx | 
															 e_SpatialTree_Data_TreeIdx | e_SpatialTree_Data_Node | 
															 e_SpatialTree_Data_Interval | e_SpatialTree_Data_BVH, 
															 NULL, NULL, 
															 m_nVertexCount, m_nFaceCount, 
															 nAssetListCount, 10, m_pDevice);
	}

	if (strcmp(elementName, "Asset") == 0 && argc == 2 && 
			strcmp(argv[0], "path") == 0)
	{
		C_gl_Asset * pAsset = new C_gl_Asset();

		pAsset->Deserialize((char *) argv[1], (I_Asset *) m_pShared);

		pAsset->Create(pAsset->nVertex(), pAsset->nPrimitive(), e_Asset_Data_Tree, m_pShared);

		pAsset->Tree()->Create(e_SpatialTree_Data_PrimitiveBI | e_SpatialTree_Data_PrimIdx | 
														e_SpatialTree_Data_TreeIdx | e_SpatialTree_Data_Node | 
														e_SpatialTree_Data_Interval | e_SpatialTree_Data_BVH, 
														pAsset->m_pPos, pAsset->m_pPosIdx, 
														pAsset->nVertex(), pAsset->nPrimitive(), 
														1, m_pShared->Tree()->nDepth(), m_pShared->Tree());

		m_AssetList.push_back(pAsset);
	}	

	if (strcmp(elementName, "MatrixWS") == 0 && argc == 2 && 
			strcmp(argv[0], "count") == 0)
	{
		int nCount = 0;
		sscanf(argv[1], "%d", &nCount);

		m_pMatrixWS = new T_Buffer_GL<matrix4x4>();
		m_pMatrixWSInverse = new T_Buffer_GL<matrix4x4>();

		m_pMatrixWS->Create(nCount, m_pDevice);
		m_pMatrixWSInverse->Create(nCount, m_pDevice);
	}	

	if (strcmp(elementName, "m4x4") == 0 && argc == 2 && 
			strcmp(argv[0], "major") == 0 && 
			elementData != NULL)
	{
		float4 pM[4];
		matrix4x4 * pWS = ((matrix4x4 *) m_pMatrixWS->hPtr()) + matrixOffset;
		matrix4x4 * pWSInv = ((matrix4x4 *) m_pMatrixWSInverse->hPtr()) + matrixOffset;

		if (strcmp(argv[1], "row") == 0) {
			sscanf(elementData, "%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f", &pM[0].x, &pM[0].y, &pM[0].z, &pM[0].w,
																															&pM[1].x, &pM[1].y, &pM[1].z, &pM[1].w,
																															&pM[2].x, &pM[2].y, &pM[2].z, &pM[2].w,
																															&pM[3].x, &pM[3].y, &pM[3].z, &pM[3].w);

			Matrix4x4SetByRow(pWS, pM[0], pM[1], pM[2], pM[3]);
			Matrix4x4Inverse(pWSInv, pWS);
		}

		if (strcmp(argv[1], "column") == 0) {
			sscanf(elementData, "%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f", &pM[0].x, &pM[1].x, &pM[2].x, &pM[3].x,
																															&pM[0].y, &pM[1].y, &pM[2].y, &pM[3].y,
																															&pM[0].z, &pM[1].z, &pM[2].z, &pM[3].z,
																															&pM[0].w, &pM[1].w, &pM[2].w, &pM[3].w);

			Matrix4x4SetByColumn(pWS, pM[0], pM[1], pM[2], pM[3]);
		}

		matrixOffset++;
	}	

	if (strcmp(elementName, "ActorList") == 0 && argc == 2 && 
			strcmp(argv[0], "count") == 0)
	{
		int nActorListCount = 0;
		sscanf(argv[1], "%d", &nActorListCount);

		m_ActorList.reserve(nActorListCount);

		if (m_pActorTree == NULL) m_pActorTree = new C_gl_SpatialTree();

		m_pActorTree->Create(e_SpatialTree_Data_PrimitiveBI | e_SpatialTree_Data_PrimIdx | 
												 e_SpatialTree_Data_Node | e_SpatialTree_Data_Interval, 
												 NULL, NULL, 0, nActorListCount, 1, 
												 m_pShared->Tree()->nDepth(), m_pShared->Tree());

		m_pActorTree->Create( e_SpatialTree_Data_TreeIdx | e_SpatialTree_Data_WeightStart |
													e_SpatialTree_Data_BVH, NULL, NULL, 0, nActorListCount, 
													1, 10, m_pDevice);
	}	

	if (strcmp(elementName, "Actor") == 0 && argc == 8 && 
			strcmp(argv[0], "assetID") == 0 &&
			strcmp(argv[2], "materialID") == 0 && 
			strcmp(argv[4], "matrixID") == 0 && 
			strcmp(argv[6], "programID") == 0 )
	{
		int nAssetID = 0;
		int nMaterialID = 0;
		int nMatrixID = 0;
		int nProgramID = 0;

		sscanf(argv[1], "%d", &nAssetID);
		sscanf(argv[3], "%d", &nMaterialID);
		sscanf(argv[5], "%d", &nMatrixID);
		sscanf(argv[7], "%d", &nProgramID);

		C_gl_Actor * pActor = new C_gl_Actor();
		pActor->Asset(m_AssetList[nAssetID]);
		pActor->BaseMaterial(m_BaseMaterialList[nMaterialID]);
		pActor->pMatrixWS( (((matrix4x4 *)m_pMatrixWS->hPtr())+nMatrixID) );
		pActor->nMatrixWS(nMatrixID);
		pActor->Program(m_ProgramList[nProgramID]);
		
		m_ActorList.push_back(pActor);
	}	

	if (strcmp(elementName, "Shader") == 0 && argc == 4 &&
			strcmp(argv[0], "type") == 0 && 
			strcmp(argv[2], "path") == 0)
	{		
		I_api_VertexShader * pVS = NULL;
		I_api_PixelShader * pPS = NULL;
		I_api_Blob * pShaderBytecode = NULL;
		I_api_Blob * pErrorMsg = NULL;
		bool result = false;
		
		if (strcmp(argv[1], "vs_5_0") == 0){
			result = m_pCommon->CompileShader(NULL, 0, (char *) argv[3], NULL, NULL, NULL, (char *) "vs_5_0", 0, &pShaderBytecode, &pErrorMsg);
			if (result) 
				result = m_pDevice->CreateVertexShader(pShaderBytecode->GetBufferPointer(), pShaderBytecode->GetBufferSize(), &pVS);
			if (result)
				m_VertexShaderList.push_back(pVS);
		}

		if (strcmp(argv[1], "ps_5_0") == 0){
			result = m_pCommon->CompileShader(NULL, 0, (char *) argv[3], NULL, NULL, NULL, (char *) "ps_5_0", 0, &pShaderBytecode, &pErrorMsg);
			if (result) 
				result = m_pDevice->CreatePixelShader(pShaderBytecode->GetBufferPointer(), pShaderBytecode->GetBufferSize(), &pPS);
			if (result)
				m_PixelShaderList.push_back(pPS);
		}
	}

	if (strcmp(elementName, "Program") == 0 && argc == 4 &&
			strcmp(argv[0], "vertex") == 0 && 
			strcmp(argv[2], "pixel") == 0)
	{		
		int vs = 0, ps = 0;
		bool result = false;

		sscanf(argv[1], "%d", &vs);
		sscanf(argv[3], "%d", &ps);

		I_api_Blob * pErrorMsg = NULL;
		I_api_Program * pProgram = NULL;
		
		result = m_pDevice->CreateProgram(m_VertexShaderList[vs], m_PixelShaderList[ps], &pProgram, &pErrorMsg);

		if (result) m_ProgramList.push_back(pProgram);
	}

	if (strcmp(elementName, "LightList") == 0 && argc == 2 &&
			strcmp(argv[0], "count") == 0)
	{
		int nLight = 0;
		sscanf(argv[1], "%d", &nLight);

		m_LightManager.Create(nLight, m_pDevice);
	}

	if (strcmp(elementName, "Light") == 0 && argc == 8 &&
		strcmp(argv[0], "type") == 0 &&  
		strcmp(argv[1], "point") == 0 && 
		strcmp(argv[2], "position") == 0 && 
		strcmp(argv[4], "radius") == 0 && 
		strcmp(argv[6], "color") == 0 )
	{
		float4 position; 
		float4 color = f4();
		sscanf(argv[3], "%f%f%f", &position.x, &position.y, &position.z);
		sscanf(argv[5], "%f", &position.w);
		sscanf(argv[7], "%f%f%f", &color.x, &color.y, &color.z);

		m_LightManager.Add(position, color);
	}

	return true;
}


bool	C_gl_SceneGraph::Serialize(char * pFileName)
{
	return true;
}


void	C_gl_SceneGraph::Build(int nType)
{
	float4 *	pActorData = (float4 *) m_pActorTree->ActorData()->hPtr();
	float2 *	ppBI[3];
	ppBI[0] = (float2 *) m_pActorTree->PrimitiveBI(0)->hPtr();
	ppBI[1] = (float2 *) m_pActorTree->PrimitiveBI(1)->hPtr();
	ppBI[2] = (float2 *) m_pActorTree->PrimitiveBI(2)->hPtr();

	int prim_offset = 0;
	int vert_offset = 0;
	int * pTracePrimIdx = (int *) m_pPosIdx->hPtr();

	for (uint iAsset = 0; iAsset < m_AssetList.size(); iAsset++) {
		int * pAssetPrimIdx = (int *) m_AssetList[iAsset]->m_pPosIdx->hPtr();
		for (int iPrim = 0; iPrim < m_AssetList[iAsset]->nPrimitive(); iPrim++)
		{
			pTracePrimIdx[prim_offset + iPrim*3+0] = pAssetPrimIdx[iPrim*3+0] + vert_offset;
			pTracePrimIdx[prim_offset + iPrim*3+1] = pAssetPrimIdx[iPrim*3+1] + vert_offset;
			pTracePrimIdx[prim_offset + iPrim*3+2] = pAssetPrimIdx[iPrim*3+2] + vert_offset;	
		}
		prim_offset+=3*m_AssetList[iAsset]->nPrimitive();
		vert_offset+=m_AssetList[iAsset]->nVertex();
	}

	for (uint iActor = 0; iActor < m_ActorList.size(); iActor++) {
		S_Box box = m_ActorList[iActor]->Asset()->Box();
		Transform(&box, &box, *m_ActorList[iActor]->pMatrixWS());

		ppBI[0][iActor] = box.Ix();
		ppBI[1][iActor] = box.Iy();
		ppBI[2][iActor] = box.Iz();

		pActorData[iActor].x = m_ActorList[iActor]->nPrimitive();
		pActorData[iActor].y = m_ActorList[iActor]->Asset()->Tree()->BVHTree()->Offset();
		pActorData[iActor].z = m_ActorList[iActor]->nMatrixWS();
		pActorData[iActor].w = m_ActorList[iActor]->nVertex();
	}

	m_pActorTree->PrimitiveAABB();

	m_pActorTree->BVHTree_Instanced_p0();
	m_pActorTree->BVHTree_p1();

	m_pShared->m_pPos->Memcpy(e_Copy_HtoD);
	m_pShared->m_pPosIdx->Memcpy(e_Copy_HtoD);
	m_pShared->m_pNml->Memcpy(e_Copy_HtoD);
}


void	C_gl_SceneGraph::Render(C_Camera * pCamera)
{
	for (uint iActor = 0; iActor < m_ActorList.size(); iActor++)
	{
		m_ActorList[iActor]->Render(m_pDevice, pCamera);
	}
}


void	C_gl_SceneGraph::RenderBVHTree(C_Camera * pCamera, int nMaxLevel, bool bAsset, bool bActor)
{
	for (uint iActor = 0; iActor < m_ActorList.size(); iActor++)
	{
		glColor3f(0, 1, 0);
		if (bAsset) ((C_gl_Actor *) m_ActorList[iActor])->RenderBVHTree(m_pDevice, pCamera, nMaxLevel);
	}

	matrix4x4 identity, view, projection;
	Matrix4x4SetIdentity(&identity);
	Matrix4x4LookAtLHR(&view, pCamera->Eye(), pCamera->At(), pCamera->Up());
	Matrix4x4PerspectiveFovGLR(&projection, pCamera->FoV(), pCamera->Asp(), pCamera->zN(), pCamera->zF());

	glColor3f(1, 0, 0);
	if (bActor) m_pActorTree->RenderBVHTree(nMaxLevel, &identity, &view, &projection, m_pDevice);
}

void	C_gl_SceneGraph::RenderBVHTreeRayTrace(C_Camera * pCamera, float3 orig, float3 dir, int maxLevel, bool empty)
{
	matrix4x4 identity, view, projection;
	Matrix4x4SetIdentity(&identity);
	Matrix4x4LookAtLHR(&view, pCamera->Eye(), pCamera->At(), pCamera->Up());
	Matrix4x4PerspectiveFovGLR(&projection, pCamera->FoV(), pCamera->Asp(), pCamera->zN(), pCamera->zF());

	matrix4x4 modelview = identity * view;
	glUseProgram(0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glLoadMatrixf((float *) &modelview);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glLoadMatrixf((float *) &projection);

	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	m_pActorTree->RenderBVHTreeRayTrace(orig, dir, maxLevel, empty);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

void C_gl_SceneGraph::TraceIndexedInstanced(I_Buffer * pOrig, I_Buffer * pDir, I_Buffer * pDepth, I_Buffer * pAsset, I_Buffer * pPrimitive, I_Buffer * pColor, bool cu)
{
	if (cu) {
		pOrig->Map(e_Map_Lock);
		pDir->Map(e_Map_Lock);
		pDepth->Map(e_Map_Lock);

		if (pAsset)
		{
			pAsset->Map(e_Map_Lock);
			pAsset->Memcpy(e_Copy_HtoD);
		}

		if (pPrimitive)
		{
			pPrimitive->Map(e_Map_Lock);
			pPrimitive->Memcpy(e_Copy_HtoD);
		}

		m_pShared->m_pPos->Map(e_Map_Lock);
		m_pShared->m_pPos->Memcpy(e_Copy_DtoH);

		m_pPosIdx->Map(e_Map_Lock);
		m_pPosIdx->Memcpy(e_Copy_HtoD);

		m_pShared->m_pTree->TreeIdx()->Map(e_Map_Lock);
		m_pShared->m_pTree->TreeIdx()->Memcpy(e_Copy_HtoD);

		m_pActorTree->TreeIdx()->Map(e_Map_Lock);
		m_pActorTree->TreeIdx()->Memcpy(e_Copy_HtoD);

		pColor->Map(e_Map_Lock);
		m_pMatrixWS->Map(e_Map_Lock);
		m_pMatrixWSInverse->Map(e_Map_Lock);

		pOrig->Memcpy(e_Copy_HtoD);
		pDir->Memcpy(e_Copy_HtoD);
		pDepth->Memcpy(e_Copy_HtoD);
		pColor->Memcpy(e_Copy_HtoD);
		m_pMatrixWS->Memcpy(e_Copy_HtoD);
		m_pMatrixWSInverse->Memcpy(e_Copy_HtoD);
		
		cuTraceIndexedInstanced(m_pActorTree, m_pShared->Tree(), 
		(matrix4x4 *)	m_pMatrixWSInverse->dPtr(),
		(float4 *) pOrig->dPtr(), 
		(float4 *) pDir->dPtr(), 
		pOrig->Size(), 
		(float4 *) m_pShared->m_pPos->dPtr(), 
		(int *) m_pPosIdx->dPtr(), 
		(int *) m_pShared->m_pTree->TreeIdx()->dPtr(), 
		(int *) m_pActorTree->TreeIdx()->dPtr(),
		(float *) pDepth->dPtr(),
		NULL, 
		(uchar4 *) pColor->dPtr());

		m_pShared->m_pPos->Unmap();
		m_pPosIdx->Unmap();
		m_pShared->m_pTree->TreeIdx()->Unmap();
		m_pActorTree->TreeIdx()->Unmap();

		pOrig->Unmap();
		pDir->Unmap();
		pDepth->Unmap();

		if (pAsset) { pAsset->Unmap(); }

		if (pPrimitive){ pPrimitive->Unmap(); }
		
		m_pMatrixWS->Unmap();
		m_pMatrixWSInverse->Unmap();

		pColor->Memcpy(e_Copy_DtoH);
		pColor->Unmap();

		cudaError_t error = cudaGetLastError();
		if (error != cudaSuccess)
			fprintf(stderr, "cuda error at %d line in %s file\n", __LINE__, __FILE__);
	}
	else
	mpTraceIndexedInstanced(m_pActorTree, m_pShared->Tree(), 
													(matrix4x4 *)	m_pMatrixWS->hPtr(),
													(float4 *) pOrig->hPtr(), 
													(float4 *) pDir->hPtr(), 
													pOrig->Size(), 
													(float4 *) m_pShared->m_pPos->hPtr(), 
													(int *) m_pPosIdx->hPtr(), 
													(int *) m_pShared->m_pTree->TreeIdx()->hPtr(), 
													(int *) m_pActorTree->TreeIdx()->hPtr(),
													(float *) pDepth->hPtr(),
													NULL, 
													(uchar4 *) pColor->hPtr());
}

void C_gl_SceneGraph::TraceInstanced(I_Buffer * pOrig, I_Buffer * pDir, I_Buffer * pDepth, I_Buffer * pAsset, I_Buffer * pPrimitive, I_Buffer * pColor, bool cu)
{
	if (cu) {
		pOrig->Map(e_Map_Lock);
		pDir->Map(e_Map_Lock);
		pDepth->Map(e_Map_Lock);

		if (pAsset)
		{
			pAsset->Map(e_Map_Lock);
			pAsset->Memcpy(e_Copy_HtoD);
		}

		if (pPrimitive)
		{
			pPrimitive->Map(e_Map_Lock);
			pPrimitive->Memcpy(e_Copy_HtoD);
		}

		m_pTriangles->Map(e_Map_Lock);
		m_pTriangles->Memcpy(e_Copy_HtoD);

		m_pShared->m_pTree->TreeIdx()->Map(e_Map_Lock);
		m_pShared->m_pTree->TreeIdx()->Memcpy(e_Copy_HtoD);

		m_pActorTree->TreeIdx()->Map(e_Map_Lock);
		m_pActorTree->TreeIdx()->Memcpy(e_Copy_HtoD);

		pColor->Map(e_Map_Lock);
		m_pMatrixWS->Map(e_Map_Lock);
		m_pMatrixWSInverse->Map(e_Map_Lock);

		pOrig->Memcpy(e_Copy_HtoD);
		pDir->Memcpy(e_Copy_HtoD);
		pDepth->Memcpy(e_Copy_HtoD);
		pColor->Memcpy(e_Copy_HtoD);
		m_pMatrixWS->Memcpy(e_Copy_HtoD);
		m_pMatrixWSInverse->Memcpy(e_Copy_HtoD);

		cuTraceInstanced(m_pActorTree, m_pShared->Tree(), 
			(matrix4x4 *)	m_pMatrixWSInverse->dPtr(),
			(float4 *) pOrig->dPtr(), 
			(float4 *) pDir->dPtr(), 
			pOrig->Size(), 
			(float2 *) m_pTriangles->dPtr(), 
			(int *) m_pShared->m_pTree->TreeIdx()->dPtr(), 
			(int *) m_pActorTree->TreeIdx()->dPtr(),
			(float *) pDepth->dPtr(),
			NULL, 
			(uchar4 *) pColor->dPtr());

		m_pTriangles->Unmap();
		m_pShared->m_pTree->TreeIdx()->Unmap();
		m_pActorTree->TreeIdx()->Unmap();

		pOrig->Unmap();
		pDir->Unmap();
		pDepth->Unmap();

		if (pAsset) { pAsset->Unmap(); }

		if (pPrimitive){ pPrimitive->Unmap(); }

		m_pMatrixWS->Unmap();
		m_pMatrixWSInverse->Unmap();

		pColor->Memcpy(e_Copy_DtoH);
		pColor->Unmap();

		cudaError_t error = cudaGetLastError();
		if (error != cudaSuccess)
			fprintf(stderr, "cuda error at %d line in %s file\n", __LINE__, __FILE__);
	}
	else
		mpTraceIndexedInstanced(m_pActorTree, m_pShared->Tree(), 
		(matrix4x4 *)	m_pMatrixWS->hPtr(),
		(float4 *) pOrig->hPtr(), 
		(float4 *) pDir->hPtr(), 
		pOrig->Size(), 
		(float4 *) m_pShared->m_pPos->hPtr(), 
		(int *) m_pPosIdx->hPtr(), 
		(int *) m_pShared->m_pTree->TreeIdx()->hPtr(), 
		(int *) m_pActorTree->TreeIdx()->hPtr(),
		(float *) pDepth->hPtr(),
		NULL, 
		(uchar4 *) pColor->hPtr());
}

void C_gl_SceneGraph::TraceIndexedInstanced(float3 RayO, float3 RayD, int RayI, I_Buffer * pDepth, I_Buffer * pAsset, I_Buffer * pPrimitive, I_Buffer * pColor)
{
	mpTraceIndexedInstanced(m_pActorTree, m_pShared->Tree(), 
													(matrix4x4 *)	m_pMatrixWS->hPtr(),
													RayO, RayD, RayI,
													(float4 *) m_pShared->m_pPos->hPtr(), 
													(int *) m_pPosIdx->hPtr(), 
													(int *) m_pShared->m_pTree->TreeIdx()->hPtr(), 
													(int *) m_pActorTree->TreeIdx()->hPtr(),
													(float *) pDepth->hPtr(),
													NULL, 
													(uchar4 *) pColor->hPtr());
}

void C_gl_SceneGraph::TraceIndexed(I_Buffer * pOrig, I_Buffer * pDir, I_Buffer * pDepth, I_Buffer * pAsset, I_Buffer * pPrimitive, I_Buffer * pColor)
{
	mpTraceIndexed(m_AssetList[0]->Tree(), 
		(float4 *) pOrig->hPtr(), 
		(float4 *) pDir->hPtr(), 
		pOrig->Size(), 
		(float4 *) m_AssetList[0]->m_pPos->hPtr(), 
		(int *) m_AssetList[0]->m_pPosIdx->hPtr(), 
		(uint *) m_AssetList[0]->Tree()->TreeIdx()->hPtr(), 
		(float *) pDepth->hPtr(),
		NULL, 
		(uchar4 *) pColor->hPtr());
}

void C_gl_SceneGraph::TraceIndexed(float3 RayO, float3 RayD, int RayI, I_Buffer * pDepth, I_Buffer * pAsset, I_Buffer * pPrimitive, I_Buffer * pColor) 
{
	mpTraceIndexed(m_AssetList[0]->Tree(), 
		RayO, RayD, RayI,
		(float4 *) m_AssetList[0]->m_pPos->hPtr(), 
		(int *) m_AssetList[0]->m_pPosIdx->hPtr(), 
		(uint *) m_AssetList[0]->Tree()->TreeIdx()->hPtr(), 
		(float *) pDepth->hPtr(),
		NULL, 
		(uchar4 *) pColor->hPtr());
}

void C_gl_SceneGraph::Shade(I_api_ShaderResourceView * pDiffuse, I_api_ShaderResourceView * pWorldPos, I_api_ShaderResourceView * pWorldNml)
{
	I_api_Resource * pDiffuseRes = NULL; 
	I_api_Resource * pWorldPosRes = NULL;
	I_api_Resource * pWorldNmlRes = NULL;
	pDiffuse->GetResource(&pDiffuseRes);
	pWorldPos->GetResource(&pWorldPosRes);
	pWorldNml->GetResource(&pWorldNmlRes);

	S_api_Mapped_Texture2D diffuseMapped, worldposMapped, worldnmlMapped;

	I_api_Texture_2D * pDiffuseTex = dynamic_cast<I_api_Texture_2D *>(pDiffuseRes);
	I_api_Texture_2D * pWorlNmlTex = dynamic_cast<I_api_Texture_2D *>(pWorldNmlRes);
	I_api_Texture_2D * pWorldPosTex = dynamic_cast<I_api_Texture_2D *>(pWorldPosRes);

	pDiffuseTex->Map(0, E_api_Map_Lock, 0, &diffuseMapped);
	pWorldPosTex->Map(0, E_api_Map_Lock, 0, &worldposMapped);
	pWorlNmlTex->Map(0, E_api_Map_Lock, 0, &worldnmlMapped);
}

void C_gl_SceneGraph::Compress()
{
	if (m_pTriangles == NULL) {
		m_pTriangles = new T_Buffer_GL<float2>;
		m_pTriangles->Create(m_nFaceCount*5, m_pDevice);
	}

	if (m_pCompressedTriangles == NULL){
		m_pCompressedTriangles = new T_Buffer_GL<float2>;
		m_pCompressedTriangles->Create(m_nFaceCount*3, m_pDevice);
	}

	S_CompressedTriangle * pComp = (S_CompressedTriangle *) m_pCompressedTriangles->hPtr();
	int * pFace = (int *) m_pPosIdx->hPtr(); // m_pShared->m_pPosIdx->hPtr();
	float4 * pPos = (float4 *) m_pShared->m_pPos->hPtr();

	float * pTri = (float *) m_pTriangles->hPtr();

	for (int i = 0; i < m_nFaceCount; i++)
	{
		int3 face = { pFace[i*3], pFace[i*3+1], pFace[i*3+2] };

		float4 pos[3] = {pPos[face.x], pPos[face.y], pPos[face.z]};

		FFloat16 x, y, z;
		x = FFloat16(pos[0].x);
		y = FFloat16(pos[0].y);
		z = FFloat16(pos[0].z);

		pComp[i].v0.x = x.Encoded;
		pComp[i].v0.y = y.Encoded;
		pComp[i].v0.z = z.Encoded;

		x = FFloat16(pos[1].x);
		y = FFloat16(pos[1].y);
		z = FFloat16(pos[1].z);
		pComp[i].v1.x = x.Encoded;
		pComp[i].v1.y = y.Encoded;
		pComp[i].v1.z = z.Encoded;

		x = FFloat16(pos[2].x);
		y = FFloat16(pos[2].y);
		z = FFloat16(pos[2].z);
		pComp[i].v2.x = x.Encoded;
		pComp[i].v2.y = y.Encoded;
		pComp[i].v2.z = z.Encoded;

		pTri[i*10+0] = pos[0].x;
		pTri[i*10+1] = pos[0].y;
		pTri[i*10+2] = pos[0].z;
		pTri[i*10+3] = pos[1].x;
		pTri[i*10+4] = pos[1].y;
		pTri[i*10+5] = pos[1].z;
		pTri[i*10+6] = pos[2].x;
		pTri[i*10+7] = pos[2].y;
		pTri[i*10+8] = pos[2].z;
		pTri[i*10+9] = 0;
	}
}